//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "pobjenum.h"
#include "pcentral.h"
#include "pprocess.h"
#include "pthread.h"
#include "pmodule.h"
#include "pseudo.h"
#include "helper.h"
#include <aura.h>

#define REMOTE_PROCESS_ALREADY_EXITED() (NULL == m_pProxy)
#define REMOTE_PROCESS_JUST_EXITED(ec) (E_PROCESS_ALREADY_EXITED == ec)

// -------- CPseudoObjectEnumerator -------------------------
PInterface CPseudoObjectEnumerator::Probe(
    /* [in] */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(IObjectEnumerator *)this;
    }
    else if (riid == EIID_IObjectEnumerator) {
        return (IObjectEnumerator *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CObjectEnumerator;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_IObjectEnumerator;
    }

    return NULL;
}

UInt32 CPseudoObjectEnumerator::AddRef(void)
{
    Int32 nRefs = m_nRefs.Increment();
    return (UInt32)nRefs;
}

UInt32 CPseudoObjectEnumerator::Release(void)
{
    Int32 nRefs = m_nRefs.Decrement();
    assert(nRefs >= 0);
    if (0 == nRefs) {
        delete this;
    }
    return (UInt32)nRefs;
}

ECode CPseudoObjectEnumerator::Aggregate(
    /* [in] */ AggrType aggrType,
    /* [in] */ PInterface pObject)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoObjectEnumerator::GetDomain(
    /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoObjectEnumerator::Current(
    /* [out] */ PInterface * ppObject)
{
    if (NULL == ppObject) {
        return E_INVALID_ARGUMENT;
    }
    return E_INVALID_OPERATION;
}

ECode CPseudoObjectEnumerator::MoveNext(
    /* [out] */ Boolean * pSucceeded)
{
    if (NULL == pSucceeded) {
        return E_INVALID_ARGUMENT;
    }
    *pSucceeded = FALSE;
    return NOERROR;
}

ECode CPseudoObjectEnumerator::Reset()
{
    return NOERROR;
}

// -------- CPseudoProcessEnumerator -----------------------------------
CPseudoProcessEnumerator::~CPseudoProcessEnumerator()
{
    if (INVALID_ENUMERATOR_ID != m_enumeratorId) {
        CPseudoCentral::Enumerator_Release(m_enumeratorId);
        m_enumeratorId = INVALID_ENUMERATOR_ID;
    }
}

ECode CPseudoProcessEnumerator::Initialize()
{
    return CPseudoCentral::Enumerator_Create(&m_enumeratorId);
}

ECode CPseudoProcessEnumerator::Current(
        /* [out] */ PInterface *ppObject)
{
    PseudoObject * pPObject = NULL;
    ProcessId processId = AURA_INVALID_PID;
    ECode ec = NOERROR;

    if (NULL == ppObject) {
        return E_INVALID_ARGUMENT;
    }

    ec = CPseudoCentral::Enumerator_GetCurrent(m_enumeratorId, &processId);
    if (FAILED(ec)) {
        return ec;
    }

    if (::IsCurrentProcessId(processId)) {
        IProcess * pProcess = NULL;
        CPseudoKernel::Process_GetCurrent(&pProcess);
        *ppObject = (PInterface)pProcess;
        return NOERROR;
    }

    CPseudoProcessFactory factory(processId);
    ec = PseudoObject::S_Create(&factory, &pPObject);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    *ppObject = pPObject->GetObject();

    return NOERROR;

ErrorExit:
    if (AURA_INVALID_PID != processId) {
        CPseudoCentral::Process_Release(processId);
        processId = AURA_INVALID_PID;
    }

    return ec;
}

ECode CPseudoProcessEnumerator::MoveNext(
        /* [out] */ Boolean *pSucceeded)
{
    if (NULL == pSucceeded) {
        return E_INVALID_ARGUMENT;
    }

    return CPseudoCentral::Enumerator_MoveNext(m_enumeratorId, pSucceeded);
}

ECode CPseudoProcessEnumerator::Reset()
{
    return CPseudoCentral::Enumerator_Reset(m_enumeratorId);
}

// --------- for CPseudoThreadEnumerator ----------------------

CPseudoThreadEnumerator::~CPseudoThreadEnumerator()
{
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
}

ECode CPseudoThreadEnumerator::Initialize()
{
    ECode ec = NOERROR;
    ec = AuraCriticalSection_Create(&m_hLock);
    if (FAILED(ec)) {
        return ec;
    }
    ec = m_pProcess->GetAllThreads(&m_pProxy);
    if (FAILED(ec)) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }

    return ec;
}

ECode CPseudoThreadEnumerator::Current(
        /* [out] */ PInterface * ppObject)
{
    IThread * pProxy = NULL;
    PseudoObject * pPObject = NULL;
    ECode ec = NOERROR;

    if (NULL == ppObject) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        Unlock(m_hLock);
        return E_INVALID_OPERATION;
    }
    ec = m_pProxy->Current((PInterface *)&pProxy);
    if (FAILED(ec)) {
        if (REMOTE_PROCESS_JUST_EXITED(ec)) {
            pProxy->Release();
            pProxy = NULL;
        }
        Unlock(m_hLock);
        return ec;
    }
    Unlock(m_hLock);

    CPseudoThreadFactory factory(m_processId, pProxy);
    ec = PseudoObject::S_Create(&factory, &pPObject);
    if (FAILED(ec)) {
        pProxy->Release();
        pProxy = NULL;
        return ec;
    }
    *ppObject = pPObject->GetObject();

    return NOERROR;
}

ECode CPseudoThreadEnumerator::MoveNext(
        /* [out] */ Boolean *pSucceeded)
{
    ECode ec = NOERROR;

    if (NULL == pSucceeded) {
        return E_INVALID_ARGUMENT;
    }

    *pSucceeded = FALSE;
    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        ec = E_INVALID_OPERATION;
        goto ErrorExit;
    }
    ec = m_pProxy->MoveNext(pSucceeded);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    Unlock(m_hLock);

    return NOERROR;

ErrorExit:
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        ec = E_INVALID_OPERATION;
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);

    return ec;
}

ECode CPseudoThreadEnumerator::Reset()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        ec = E_INVALID_OPERATION;
        goto ErrorExit;
    }
    ec = m_pProxy->Reset();
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    Unlock(m_hLock);

    return NOERROR;

ErrorExit:
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        ec = E_INVALID_OPERATION;
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);

    return ec;
}

// --------- for CPseudoModuleEnumerator ----------------------
CPseudoModuleEnumerator::~CPseudoModuleEnumerator()
{
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
}

ECode CPseudoModuleEnumerator::Initialize()
{
    ECode ec = NOERROR;
    ec = AuraCriticalSection_Create(&m_hLock);
    if (FAILED(ec)) {
        return ec;
    }
    ec = m_pProcess->GetAllModules(&m_pProxy);
    if (FAILED(ec)) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }

    return ec;
}

ECode CPseudoModuleEnumerator::Current(
        /* [out] */ PInterface * ppObject)
{
    IModule * pProxy = NULL;
    PseudoObject * pPObject = NULL;
    ECode ec = NOERROR;

    if (NULL == ppObject) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        Unlock(m_hLock);
        return E_INVALID_OPERATION;
    }
    ec = m_pProxy->Current((PInterface *)&pProxy);
    if (FAILED(ec)) {
        if (REMOTE_PROCESS_JUST_EXITED(ec)) {
            pProxy->Release();
            pProxy = NULL;
        }
        Unlock(m_hLock);
        return ec;
    }
    Unlock(m_hLock);

    CPseudoModuleFactory factory(m_processId, pProxy);
    ec = PseudoObject::S_Create(&factory, &pPObject);
    if (FAILED(ec)) {
        pProxy->Release();
        pProxy = NULL;
        return ec;
    }
    *ppObject = pPObject->GetObject();

    return NOERROR;
}

ECode CPseudoModuleEnumerator::MoveNext(
        /* [out] */ Boolean *pSucceeded)
{
    ECode ec = NOERROR;

    if (NULL == pSucceeded) {
        return E_INVALID_ARGUMENT;
    }

    *pSucceeded = FALSE;
    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        ec = E_INVALID_OPERATION;
        goto ErrorExit;
    }
    ec = m_pProxy->MoveNext(pSucceeded);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    Unlock(m_hLock);

    return NOERROR;

ErrorExit:
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        ec = E_INVALID_OPERATION;
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);

    return ec;
}

ECode CPseudoModuleEnumerator::Reset()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        ec = E_INVALID_OPERATION;
        goto ErrorExit;
    }
    ec = m_pProxy->Reset();
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    Unlock(m_hLock);

    return NOERROR;

ErrorExit:
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        ec = E_INVALID_OPERATION;
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);

    return ec;
}

// --------------------------------------------------------------

ECode CPseudoEnumeratorBuilder::BuildForDummy(
        /* [out] */ IObjectEnumerator ** ppEnumerator)
{
    CPseudoObjectEnumerator * pEnumerator = NULL;

    assert(NULL != ppEnumerator);

    pEnumerator = new CPseudoObjectEnumerator();
    if (NULL == pEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    *ppEnumerator = pEnumerator;
    (*ppEnumerator)->AddRef();

    return NOERROR;
}

ECode CPseudoEnumeratorBuilder::BuildForProcess(
        /* [out] */ IObjectEnumerator ** ppEnumerator)
{
    CPseudoProcessEnumerator * pEnumerator = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppEnumerator);

    pEnumerator = new CPseudoProcessEnumerator();
    if (NULL == pEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    ec = pEnumerator->Initialize();
    if (FAILED(ec)) {
        delete pEnumerator;
        pEnumerator = NULL;
        return ec;
    }

    *ppEnumerator = pEnumerator;
    (*ppEnumerator)->AddRef();

    return NOERROR;
}

ECode CPseudoEnumeratorBuilder::BuildForThread(
        /* [in] */ ProcessId processId,
        /* [in] */ IProcess * pProcess,
        /* [out] */ IObjectEnumerator ** ppEnumerator)
{
    CPseudoThreadEnumerator * pEnumerator = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppEnumerator);

    pEnumerator = new CPseudoThreadEnumerator(processId, pProcess);
    if (NULL == pEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    ec = pEnumerator->Initialize();
    if (FAILED(ec)) {
        delete pEnumerator;
        pEnumerator = NULL;
        return ec;
    }

    *ppEnumerator = pEnumerator;
    (*ppEnumerator)->AddRef();

    return NOERROR;
}

ECode CPseudoEnumeratorBuilder::BuildForModule(
        /* [in] */ ProcessId processId,
        /* [in] */ IProcess * pProcess,
        /* [out] */ IObjectEnumerator ** ppEnumerator)
{
    CPseudoModuleEnumerator * pEnumerator = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppEnumerator);

    pEnumerator = new CPseudoModuleEnumerator(processId, pProcess);
    if (NULL == pEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    ec = pEnumerator->Initialize();
    if (FAILED(ec)) {
        delete pEnumerator;
        pEnumerator = NULL;
        return ec;
    }

    *ppEnumerator = pEnumerator;
    (*ppEnumerator)->AddRef();

    return NOERROR;
}

